<template>
	<div class="table-box">
		<div class="table">
			<el-table class="none-el-table__placeholder" ref="tableref" :show-summary="props.showSummary"
				v-loading="props.loading" :data="props.data" size="large"
				:header-cell-style="{ background: 'rgba(245, 247, 250, 1)' }" :stripe="props.stripe"
				:border="props.border" style="width: 100%;" height="100%"
				:highlight-current-row="props.highlightCurrentRow" :lazy="props.lazy" :load="props.load"
				:tree-props="props.treeProps" row-key="id" :summary-method="props.summaryMethod"
				:span-method="props.spanMethod" :row-class-name="props.rowClassName" :show-overflow-tooltip="true"
				:cell-class-name="props.cellClassName" @current-change="tableCurrentChange" @sort-change="sortChange"
				@row-click="rowClick" @row-dblclick="rowDblclick" @filterChange="filterChange"
				@expand-change="expandChange" @cell-mouse-enter="cellMouseEnter" @cell-mouse-leave="cellMouseLeave"
				@selection-change="handleSelectionChange" @select="handleSelect" @select-all="handleSelectAll"
				:cell-style="getCellStyle">

				<!-- 表格列 默认只有 任务名称 状态 开始时间 结束时间 -->
				<slot name="list">
					<el-table-column fixed="left" label="任务名称" prop="text" width="120" />
					<el-table-column fixed="left" label="状态" prop="statusLabel" width="80" />
					<el-table-column fixed="left" label="开始时间" prop="start_date" width="120" />
					<el-table-column fixed="left" label="结束时间" prop="end_date" width="120" />
				</slot>
				<!-- 生成日期列 -->
				<template v-if="dateType == 'year'">
					<el-table-column v-for="item in dateCols" :label="item.label">
						<template #default="scope">
							<ganttBar v-if="showBar(scope.row,item)" :data="getBarWitch(scope)" :row="scope.row"
								@mousemove.stop="barHover(scope.row,'bar')" @mouseleave="barHoverLeave()"></ganttBar>
							<ganttPlanBar v-if="showPlanBar(scope.row,item) " :data="getPlanBarWidth(scope)"
								:row="scope.row" @mousemove.stop="barHover(scope.row,'planBar')"
								@mouseleave="barHoverLeave()"></ganttPlanBar>
						</template>
					</el-table-column>
				</template>
				<template v-else>
					<el-table-column v-for="item in dateCols" :label="item.label" :key="item.value">
						<el-table-column v-for="it in item.children" :label="it.label" :key="item.value">
							<template #default="scope">
								<ganttBar v-if="showBar(scope.row,it)" :data="getBarWitch(scope)" :row="scope.row"
									:dateType="dateType" :tableref="tableref" :cellIndex="scope.cellIndex"
									@mousemove.stop="barHover(scope.row,'bar')" @mouseleave="barHoverLeave()">
								</ganttBar>
								<ganttPlanBar v-if="showPlanBar(scope.row,it) " :data="getPlanBarWidth(scope)"
									:dateType="dateType" :tableref="tableref" :row="scope.row"
									@mousemove.stop="barHover(scope.row,'planBar')" @mouseleave="barHoverLeave()">
								</ganttPlanBar>
							</template>
						</el-table-column>
					</el-table-column>
				</template>


				<template #empty>
					<!-- <img :src="ndImgsrc" alt="" style="max-height: 320px;height: calc(100% - 86px);"> -->
					<p>暂无数据</p>
				</template>
			</el-table>
		</div>
		<div class="paged">
			<!-- 下面pagesize pageno  使用v-model 指令可以使props 的属性值具有响应性，能直接修改父组件上的pageconfig 的值，免去了使用emit（）函数 -->
			<el-pagination v-model:page-size="props.pageConfig.pageSize" v-model:current-page="props.pageConfig.pageNo"
				small background layout=" prev, pager, next,total, sizes" :total="props.pageConfig.total"
				v-if="props.showPaged" :page-sizes="props.pageSizes" @size-change="handleSizeChange"
				@current-change="handleCurrentChange" />
		</div>

		<el-tooltip v-model:visible="visible" :content="tipsContent" raw-content placement="bottom" effect="light"
			virtual-triggering :virtual-ref="triggerRef" />
	</div>
</template>
<script setup>
	import {
		ref,
		reactive,
		onMounted,
		watch,
		onUnmounted,
		computed
	} from "vue";
	// import ndImgsrc from '@/assets/img/nodata.png'; // 图片加载
	import {
		dayjs
	} from 'element-plus'
	import ganttBar from './ganttBar.vue'
	import ganttPlanBar from './ganttPlanBar.vue'
	const tableref = ref()
	const emit = defineEmits(['sizeChange', 'currentChange', 'sortChange', 'rowClick', 'rowDblclick',
		'filterChange', 'expandChange', 'cellMouseEnter', 'cellMouseLeave', 'selectionChange',
		'select', 'selectAll', 'tableCurrentChange'
	])
	const props = defineProps({
		pageConfig: Object,
		data: Array,
		loading: Boolean,
		lazy: Boolean,
		load: Function,
		treeProps: Object,
		border: Boolean,
		showSummary: Boolean,
		summaryMethod: Function,
		spanMethod: Function,
		highlightCurrentRow: Boolean,
		stripe: Boolean,
		rowClassName: Function,
		cellClassName: Function,
		// cellStyle: Function,
		rowKey: {
			type: String,
			default: 'id'
		},
		showPaged: {
			type: Boolean,
			default: true
		},
		useIndex: {
			type: Boolean,
			default: false
		},
		pageSizes: {
			type: Array,
			default: [10, 20, 30, 40, 50, 100]
		},

		//甘特图的相关属性
		dateType: {
			type: String,
			default: 'date'
		},
		tips: String,
		planTips: String
	})



	//-----------==============================================================>>>计算日期列
	// 递归编列数据，获取最早的日期和最晚日期，然后通过dayjs 组合出年月日的二维数组
	watch(() => props.data, (n, o) => {
		setDateCols()
	})
	let allDateRange = []

	function getDateArea() {
		let earyStart = null,
			lastEnd = null
		if (props.data && props.data.length > 0) {
			props.data.forEach(item => {
				digui(item)
			})

			// 为了样式兼容
			// 如果最后一天为当月的第一天，结束时间加一天
			// 开始时间为当月第一天，开始时间减一天
			if (dayjs(lastEnd).startOf('month').isSame(lastEnd, 'day')) {
				lastEnd = dayjs(lastEnd).add(1, 'day').valueOf()
			}
			if (dayjs(earyStart).endOf('month').isSame(earyStart, 'day')) {
				earyStart = dayjs(earyStart).subtract(1, 'day').valueOf()
			}
		} else {
			// 当没有数据的时候可以使用当前月份作为日期区间
			earyStart = dayjs().startOf('month').valueOf()
			lastEnd = dayjs().endOf('month').valueOf()
		}

		function digui(obj) {
			// 吧日期转换为时间戳比较大小，取最小值为开始时间,最大值为结束时间
			let sd = obj.start_date ? dayjs(obj.start_date).valueOf() : null
			let psd = obj.plan_start_date ? dayjs(obj.plan_start_date).valueOf() : null
			let ed = obj.end_date ? dayjs(obj.end_date).valueOf() : null
			let ped = obj.plan_end_date ? dayjs(obj.plan_end_date).valueOf() : null

			let small = null,
				big = null
			if (sd && psd && sd >= psd) {
				small = psd
			} else {
				small = sd
			}
			if (sd && !psd) {
				small = sd
			}
			if (psd && !sd) {
				small = psd
			}

			if (ed && ped && ed >= ped) {
				big = ed
			} else {
				big = ped
			}
			if (ed && !ped) {
				big = ed
			}
			if (ped && !ed) {
				big = psd
			}

			if (!earyStart || (earyStart && earyStart > small)) {
				earyStart = small
			}
			if (!lastEnd || (lastEnd && lastEnd < big)) {
				lastEnd = big
			}

			if (obj.children && obj.children.length > 0) {
				obj.children.forEach(item => {
					digui(item)
				})
			}

		}
		return [earyStart, lastEnd]
	}
	// 根据最早开始时间和最晚结束时间 生成日期列
	const dateCols = ref([])

	function setDateCols() {
		// date 一列表示一天  父级显示 2022-02
		// month  一列表示以个月  父级显示 2022 
		let [start, end] = getDateArea() // 返回的为时间戳的值
		let startdata = dayjs(start)
		let enddata = dayjs(end)
		let dates = [],
			months = [],
			years = [],
			cols = []
		if (props.dateType == 'date') {
			// 开始结束时间获取这之间的所有日期，
			// 然后再按照月份分组 

			while (startdata.isBefore(enddata) || startdata.isSame(enddata, 'day')) {
				dates.push(startdata.clone().format("YYYY-MM-DD"))
				months.push(startdata.clone().format("YYYY-MM"))
				startdata = startdata.add(1, 'day');
			}
			months = [...new Set(months)]
			cols = months.map(item => {
				let children = []
				dates.forEach(it => {
					if (it.includes(item)) {
						children.push({
							label: it.replace(item + '-', ''),
							value: it
						})
					}
				})
				return {
					label: item,
					children: children
				}
			})
		}

		if (props.dateType == 'month') {
			let monthery = startdata.startOf('month')

			while (monthery.isBefore(enddata) || monthery.isSame(enddata, 'month')) {
				years.push(monthery.clone().format("YYYY"))
				months.push(monthery.clone().format("YYYY-MM"))
				monthery = monthery.add(1, 'month');
			}
			years = [...new Set(years)]

			cols = years.map(item => {
				let children = []
				months.forEach(it => {
					if (it.includes(item)) {
						children.push({
							label: it.replace(item + '-', '') + '月',
							value: it
						})
					}
				})
				return {
					label: item + '年',
					children: children
				}
			})

		}

		if (props.dateType == 'year') {
			let yearstart = startdata.startOf('year')

			while (yearstart.isBefore(enddata) || yearstart.isSame(enddata, 'year')) {
				years.push(yearstart.clone().format("YYYY"))
				yearstart = yearstart.add(1, 'year');
			}

			cols = years.map(item => {
				return {
					label: item + '年',
					value: item
				}
			})
		}
		dateCols.value = cols

	}

	// setDateCols()
	watch(() => props.dateType, (n, o) => {
		setDateCols()
	}, {
		immediate: true
	})

	function showBar(row, col) {
		if (props.dateType == 'date') {
			return row.start_date == col.value
		} else if (['month', 'year'].includes(props.dateType)) {
			return row.start_date.includes(col.value)
		}

	}

	function showPlanBar(row, col) {

		if (props.dateType == 'date') {
			return row.plan_start_date && row.plan_end_date && row.plan_start_date == col.value

		} else if (['month', 'year'].includes(props.dateType)) {
			return row.plan_start_date && row.plan_end_date && row.plan_start_date.includes(col.value)
		}
	}

	// 计算两列之间的距离 设置为bar 长度
	function getBarWitch(scope, col) {

		let barWidth = 0
		const cssStartIndex = scope.cellIndex + 1
		let cssEndIndex = null,
			startCol = tableref.value.$el.querySelector(`.el-table__row .el-table__cell:nth-child(${cssStartIndex})`),
			endCol = null
		if (props.dateType == 'date') {
			let duration = dayjs(scope.row.end_date).diff(dayjs(scope.row.start_date), 'day')
			cssEndIndex = cssStartIndex + duration
		}
		if (props.dateType == 'month') {
			// 根据开始 日期和结束日期，计算这之间有多少个月份，
			let endDate = scope.row.end_date ? dayjs(scope.row.end_date).format('YYYY-MM-DD') : dayjs(new Date()).format(
				'YYYY-MM-DD')

			let months = 0
			let start = dayjs(scope.row.start_date)
			while (start.isBefore(endDate)) {
				months++
				start = start.add(1, 'month')
			}
			cssEndIndex = cssStartIndex + months


		}
		if (props.dateType == 'year') {
			let endDate = scope.row.end_date ? dayjs(scope.row.end_date) : dayjs(new Date())


			let startDate = dayjs(scope.row.start_date)

			let year = endDate.diff(startDate, 'year')

			cssEndIndex = cssStartIndex + year
		}

		endCol = tableref.value.$el.querySelector(`.el-table__row .el-table__cell:nth-child(${cssEndIndex})`)
		if (startCol && endCol) {
			const c1 = startCol.getBoundingClientRect()
			const c2 = endCol.getBoundingClientRect()
			barWidth = c2.right - c1.left
		}


		return {
			barWidth
		}
	}

	function getPlanBarWidth(scope) {
		let width = 0
		if (scope.row.plan_start_date && scope.row.plan_end_date) {
			let planDate1 = dayjs(scope.row.plan_start_date)
			let planDate2 = dayjs(scope.row.plan_end_date)
			let duration = null
			if (props.dateType == "date") {
				duration = planDate2.diff(planDate1, 'day')
			} else if (props.dateType == "month") {
				duration = planDate2.diff(planDate1, 'month')
			} else if (props.dateType == "year") {
				duration = planDate2.diff(planDate1, 'year')
			}
			const cssStartIndex = scope.cellIndex + 1
			const cssEndIndex = cssStartIndex + duration
			const startCol = tableref.value.$el.querySelector(`.el-table__row .el-table__cell:nth-child(${cssStartIndex})`)
			const endCol = tableref.value.$el.querySelector(`.el-table__row .el-table__cell:nth-child(${cssEndIndex})`)
			if (startCol && endCol) {
				const c1 = startCol.getBoundingClientRect()
				const c2 = endCol.getBoundingClientRect()
				width = c2.right - c1.left
			}
			return width
		} else {
			return 0
		}

	}

	// =======================================>>>hover 事件
	// 设置提示的内容
	const hoverRow = ref({})
	const tipsContent = computed(() => {
		let str = ''
		if (hoverBarType.value == 'bar') {
			str = props.tips || ''
		}
		if (hoverBarType.value == 'planBar') {
			str = props.planTips || ''
		}

		if (!str) return ''
		let tipstext = str.replace(/{([^}]+)}/g, function(match, group1) {
			return hoverRow.value[group1] || ''
		})
		return tipstext

	})

	// 控制tips 的定位
	const visible = ref(false)
	const triggerRef = ref({
		getBoundingClientRect() {
			return position.value
		}
	})

	const position = ref({
		top: 0,
		left: 0,
		bottom: 0,
		right: 0,
	})

	const mousemoveHandler = (e) => {
		position.value = DOMRect.fromRect({
			width: 0,
			height: 0,
			x: e.clientX,
			y: e.clientY,
		})
	}
	let hoverBarType = ref('')

	function barHover(row, type) {
		hoverRow.value = row
		hoverBarType.value = type
		if (type == 'bar') {
			if (props.tips) {
				visible.value = true
			}
		}
		if (type == 'planBar') {
			if (props.planTips) {
				visible.value = true
			}
		}

	}

	function barHoverLeave() {
		visible.value = false
	}


	//================================================>>>🐓🦜↓↓↓↓↓↓↓ el-table 的相关回调事件


	const sortChange = ({
		column,
		prop,
		order
	}) => {

		emit('sortChange', {
			column,
			prop,
			order
		})
	}
	const handleSizeChange = (val) => {
		//分页大小
		emit('sizeChange', val)
	}
	const handleCurrentChange = (val) => {
		// 改变页码
		emit('currentChange', val)
	}
	// 行点击
	function rowClick(r, c, e) {
		emit('rowClick', r, c, e)
	}
	// 行双击
	function rowDblclick(r, c, e) {
		emit('rowDblclick', r, c, e)
	}
	//筛选
	function filterChange(filters) {
		emit('filterChange', filters)
	}
	// 展开
	function expandChange(row, expandedRows) {
		emit('expandChange', row, expandedRows)
	}

	function cellMouseEnter(row, column, cell, event) {
		emit('cellMouseEnter', row, column, cell, event)
	}

	function cellMouseLeave(row, column, cell, event) {
		emit('cellMouseLeave', row, column, cell, event)
	}

	function handleSelectionChange(val) {
		emit('selectionChange', val)
	}

	function handleSelect(selection, row) {
		emit('select', selection, row)
	}

	function handleSelectAll(selection) {
		emit('selectAll', selection)
	}
	// 单选的时候监听选中并返回数据
	function tableCurrentChange(selection) {
		emit('tableCurrentChange', selection)
	}
	// 获取选中行
	const getSelectionRows = () => {
		let rows = tableref.value.getSelectionRows()
		return rows
	}
	const toggleRowExpansion = () => {
		return tableref.value.toggleRowExpansion()
	}
	// 设置选中行
	const setCurrentRow = (row) => {
		return tableref.value.setCurrentRow(row)
	}
	// 设置选择器的勾选行
	const toggleRowSelection = (row, state = true) => {
		return tableref.value.toggleRowSelection(row, state);
	}
	// 清除选择器的勾选
	const clearSelection = () => {
		return tableref.value.clearSelection();
	}
	// 向父组件暴露方法，父组件可以通过ref对象调用这些方法
	defineExpose({
		getSelectionRows,
		toggleRowExpansion,
		setCurrentRow,
		tableref,
		toggleRowSelection,
		clearSelection
	})


	onMounted(() => {
		document.addEventListener('mousemove', mousemoveHandler)
	})
	onUnmounted(() => {
		document.removeEventListener('mousemove', mousemoveHandler)
	})
</script>
<style scoped>
	:deep(.el-table .el-table__cell) {
		z-index: auto;
	}

	:deep(.el-table-fixed-column--left) {
		z-index: 2 !important;
	}

	.table-box {
		width: 100%;
		height: 100%;
		display: grid;
		grid-template-rows: auto min-content;
		/* grid-template-rows: auto 50px; */
	}

	.table-box>* {
		overflow: hidden;
	}

	.paged {
		padding-top: 14px;
	}

	:deep(.el-pagination) {
		justify-content: flex-end;
	}
</style>